﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Red.Controls.Diagrams
{
    /// <summary>
    /// Class which displays red cross over the connection line. 
    /// It symbolizes disabled connection.
    /// </summary>
    public class DisabledConnectionIndicator : Shape
    {
        #region Dependency property definitions

        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register( "Points", typeof( PointCollection ), typeof( DisabledConnectionIndicator ),
                new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender ) );

        public static readonly DependencyProperty IsActiveProperty =
            DependencyProperty.Register( "IsActive", typeof( bool ), typeof( DisabledConnectionIndicator ),
                new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.AffectsRender ) );

        #endregion Dependency property definitions

        #region Properties

        /// <summary>
        /// The intermediate points that make up the line between the start and the end.
        /// </summary>
        public PointCollection Points
        {
            get { return ( PointCollection )GetValue( PointsProperty ); }
            set { SetValue( PointsProperty, value ); }
        }

        /// <summary>
        /// Specifies if connection is active or inactive (with cross in the middle of the line).
        /// </summary>
        public bool IsActive
        {
            get { return ( bool )GetValue( IsActiveProperty ); }
            set { SetValue( IsActiveProperty, value ); }
        }

        #endregion Properties

        #region Protected methods

        protected override Geometry DefiningGeometry
        {
            get
            {
                if ( Points == null || Points.Count < 2 || IsActive )
                {
                    return new GeometryGroup();
                }

                var geometry = GenerateGeometry();
                var group = new GeometryGroup();
                group.Children.Add( geometry );

                return group;
            }
        }

        protected Geometry GenerateGeometry()
        {
            var pathGeometry = new PathGeometry();

            if ( Points.Count == 2 || Points.Count == 3 )
            {
                // Make a straight line.
                var fig = new PathFigure { IsClosed = false, IsFilled = false, StartPoint = Points[ 0 ] };

                for ( var i = 1; i < Points.Count; ++i )
                {
                    fig.Segments.Add( new LineSegment( Points[ i ], true ) );
                }

                pathGeometry.Figures.Add( fig );
            }
            else
            {
                var adjustedPoints = new PointCollection { Points[ 0 ] };
                for ( var i = 1; i < Points.Count; ++i )
                {
                    adjustedPoints.Add( Points[ i ] );
                }

                if ( adjustedPoints.Count == 4 )
                {
                    if ( !IsActive )
                    {
                        var centerPoint = PointOnBezier( adjustedPoints[ 0 ], adjustedPoints[ 1 ], adjustedPoints[ 2 ], adjustedPoints[ 3 ], 0.5 );

                        var backslashFig = new PathFigure { IsClosed = false, IsFilled = false, StartPoint = new Point( centerPoint.X - 10, centerPoint.Y - 10 ) };
                        backslashFig.Segments.Add( new LineSegment( new Point( centerPoint.X + 10, centerPoint.Y + 10 ), true ) );
                        pathGeometry.Figures.Add( backslashFig );

                        var slashFig = new PathFigure { IsClosed = false, IsFilled = false, StartPoint = new Point( centerPoint.X - 10, centerPoint.Y + 10 ) };
                        slashFig.Segments.Add( new LineSegment( new Point( centerPoint.X + 10, centerPoint.Y - 10 ), true ) );
                        pathGeometry.Figures.Add( slashFig );
                    }
                }
            }

            return pathGeometry;
        }

        #endregion Protected methods

        #region Private methods

        private static Point PointOnBezier( Point P0, Point P1, Point P2, Point P3, double t )
        {
            return new Point(
              Math.Pow( ( 1 - t ), 3 ) * P0.X + 3 * Math.Pow( ( 1 - t ), 2 ) * t * P1.X + 3 * ( 1 - t ) * Math.Pow( t, 2 ) * P2.X + Math.Pow( t, 3 ) * P3.X,
              Math.Pow( ( 1 - t ), 3 ) * P0.Y + 3 * Math.Pow( ( 1 - t ), 2 ) * t * P1.Y + 3 * ( 1 - t ) * Math.Pow( t, 2 ) * P2.Y + Math.Pow( t, 3 ) * P3.Y
            );
        }

        #endregion Private methods
    }
}
